#include "mpvplayer.h"
#include "util.h"

#include <QWidget>
#include <QDir>
#include <QProcess>


static void wakeup(void* ctx) {
    MpvPlayer* mpv = (MpvPlayer*)ctx;
    emit mpv->mpvEvents();
}

MpvPlayer::MpvPlayer(QWidget* videoRenderWnd, QObject *parent)
    : QObject{parent}
{
    //1. 设置程序区域
    std::setlocale(LC_NUMERIC, "C");

    //2. 创建MPV实例
    mpv = mpv_create();
    if(mpv == nullptr) {
        LOG() << "mpv实例创建失败";
        return ;
    }

    //3. 设置选项, 如指定视频渲染窗口
    if(videoRenderWnd) {
        int64_t wid = videoRenderWnd->winId();
        mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid);
    } else {

    }

    //4. 订阅属性
    mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_INT64);
    mpv_observe_property(mpv, 0, "duration", MPV_FORMAT_DOUBLE);

    //5. 设置回调函数
    mpv_set_wakeup_callback(mpv, wakeup, this);

    connect(this, &MpvPlayer::mpvEvents, this, &MpvPlayer::onMpvEvents);

    //6. 初始化
    if(mpv_initialize(mpv) < 0) {
        LOG() << "mpv实例初始化失败";
        mpv_destroy(mpv);
        mpv = nullptr;
        return ;
    }
}

MpvPlayer::~MpvPlayer()
{
    if(mpv) {
        mpv_destroy(mpv);
        mpv = nullptr;
    }
}

void MpvPlayer::startPlay(const QString &videoPath)
{
    // 加载视频文件
    const QByteArray fileName = videoPath.toLocal8Bit();
    const char* args[] = {"loadfile", fileName.data(), NULL};
    mpv_command_async(mpv, 0, args);
}

void MpvPlayer::play()
{
    int pause = 0;
    mpv_set_property_async(mpv, 0, "pause", MPV_FORMAT_FLAG, &pause);
}

void MpvPlayer::pause()
{
    int pause = 1;
    mpv_set_property_async(mpv, 0, "pause", MPV_FORMAT_FLAG, &pause);
}

void MpvPlayer::setPlaySpeed(double speed)
{
    mpv_set_property_async(mpv, 0, "speed", MPV_FORMAT_DOUBLE, &speed);
}

void MpvPlayer::setVolume(int64_t volume)
{
    mpv_set_property_async(mpv, 0, "volume", MPV_FORMAT_INT64, &volume);
}

void MpvPlayer::setCurrentPlayPosition(int64_t poition)
{
    mpv_set_property_async(mpv, 0, "time-pos", MPV_FORMAT_INT64, &poition);
}

int64_t MpvPlayer::getPlayTime()
{
    return curPlayTime;
}

QString MpvPlayer::getVideoFirstFrame(const QString &videoPath)
{
    QString ffmpegPath = QDir::currentPath() + "/ffmpeg/ffmpeg.exe";
    QString firstFrame = QDir::currentPath() + "/firstFrame.png";

    // 构造截图命令
    // 注意：不要将参数的参数对应的值放到一个字符串中
    // 猜测：ffmpeg工具在解析命令时，可能是将参数的和值分开来解析的，即需要先解析出参数，然后在解析出参数的值
    // 放到一个字符串中，可能就会被当成某个参数 或者 某个参数的值来进行处理
    QStringList cmd;
    cmd<<"-ss"<<"00:00:00"
        <<"-i"<< videoPath
        <<"-vframes" << "1"
        <<firstFrame;

    // 创建进程，让该进程调用ffmpeg工具完成截图
    QProcess ffmpegProcess;
    ffmpegProcess.start(ffmpegPath, cmd);

    // 等待进程截图完成, -1: 无限等待，直到进程结束
    if(!ffmpegProcess.waitForFinished(-1)){
        LOG()<<"ffmpeg 进程执行失败";
        return "";
    }

    // 返回视频首帧图的路径
    return firstFrame;
}

void MpvPlayer::onMpvEvents()
{
    // 循环处理每个事件, 直到事件队列为空
    while(mpv) {
        mpv_event* event = mpv_wait_event(mpv, 0);
        if(event->event_id == MPV_EVENT_NONE) {
            // 没有事件了
            break;
        }
        handleMpvEvent(event);
    }
}

void MpvPlayer::handleMpvEvent(mpv_event *event)
{
    switch(event->event_id) {
        case MPV_EVENT_PROPERTY_CHANGE:
        {
            // 属性变化
            mpv_event_property* eventProperty = (mpv_event_property*)event->data;
            if(nullptr == eventProperty->data){
                return ;
            }
            if(strcmp(eventProperty->name, "time-pos") == 0){
                // 获取当前分片的起始播放时间
                double segmentStartTime = 0;
                mpv_get_property(mpv, "demuxer-start-time", MPV_FORMAT_DOUBLE, &segmentStartTime);

                // 获取当前分片内的播放时间
                double segmentCurrentTime = 0;
                mpv_get_property(mpv, "time-pos", MPV_FORMAT_DOUBLE, &segmentCurrentTime);

                curPlayTime = (int64_t)(segmentStartTime + segmentCurrentTime) - 1;

                // 发生信号，通知界面更新当前播放时间
                emit playPositionChanged(curPlayTime);
            } else if(0 == strcmp(eventProperty->name, "duration")) {
                int64_t duration = (int64_t)*(double*)eventProperty->data;
                emit durationChanged(duration);
            }
            break;
        }
        case MPV_EVENT_END_FILE: {
            mpv_event_end_file*endFile = (mpv_event_end_file*)event->data;
            if(endFile->reason == MPV_END_FILE_REASON_EOF){
                // 检测是否最后一个视频分片播放结束
                int64_t playlistCount = -1;
                int64_t playlistPos = -1;
                mpv_get_property(mpv, "playlist-count", MPV_FORMAT_INT64, &playlistCount);
                mpv_get_property(mpv, "playlist-pos", MPV_FORMAT_INT64, &playlistPos);

                if(playlistCount > 0 && playlistPos == playlistCount-1){
                    LOG()<<"整个视频播放结束";
                    emit endOfPlaylist();
                }else{
                    LOG()<<"单个视频分片播放结束";
                }
            }
            break;
            break;
        }
        case MPV_EVENT_SHUTDOWN: {
            // mpv 实例​​即将关闭或终止时​​触发，用于通知应用程序进行一些必要的清理工作
            mpv_destroy(mpv);
            mpv = nullptr;
            break;
        }
        default:
            break;
    }
}


